/**
 * listeners:
 * addExtraDsValues
 */
ria.buildList = function(spec) {
    if(!spec) {
        spec = {};
    }
    if(!spec.extraTplValues) {
        spec.extraTplValues = {};
    }
    var fillTpl = function(html) { // "private method"
        spec.element.html(html);
        if(spec.element.fillTemplate.rptInstance) {
            spec.element.fillTemplate.rptInstance = null; //clear element template cache.
        }
        return this;
    };



    var ret = {
        display : function(actualView) {

            if(actualView) {
                this.setActualView(actualView);
            }
            var ds = clone(spec.ds);
            if(spec.extraTplValues) {
                for(i in spec.extraTplValues) {
                    ds[i] = spec.extraTplValues[i];
                }
            }
            var actualTplName = spec.views[spec.actualView].tpl;
            var actualItemDecoratorName = spec.views[spec.actualView].itemDecorator;
            this.addExtraTplValuesBeforeDisplay(ds);
            if(spec.itemDecorators == undefined || spec.itemDecorators[actualItemDecoratorName] == undefined) {
                throw "Decorator " + actualDecoratorName + " is not defined";
            }
            // roda pelos itens e renderiza cada um primeiro
            var html = '';
            //var originalDs = spec.riaObject.getDs();
            spec.riaObject.bind(
                    'extraValues',
                    function(ds) {
                        for(name in spec.extraItemTplValues) {
                            var val = spec.extraItemTplValues[name].replace('${dsId}',ds.id);
                            ds[name] = val.replace('${count}',i);
                        }
                    }
            );
            for(i in spec.itemsDs) {
                var dsItem = spec.itemsDs[i];
                spec.riaObject.setDs(dsItem).setElement(spec.element).display();
                ds._decorator_content = spec.element.html();
                spec.element.fillTemplate.rptInstance = null;
                fillTpl(spec.itemDecorators[actualItemDecoratorName]);
                var result = {parsedTemplate:''};
                ds['_listItemId'] = spec.itemId + dsItem.id;
                spec.element.fillTemplate(ds,result);
                html += result.parsedTemplate;
            }
            //spec.riaObject.clearListeners('extraValues');
            //spec.riaObject.setDs(originalDs);
            ds._decorator_content = html;
            spec.element.fillTemplate.rptInstance = null;
            fillTpl(spec.tpls[actualTplName]);
            spec.element.fillTemplate(ds);
            if( this.postDisplay ) { this.postDisplay(spec, json); };
            return this;
        },
        setJsObjName : function(jsObjName) {spec.jsObjName = jsObjName; return this;},
        setExtraItemTplValues : function(values) {
            spec.extraItemTplValues = values;
            return this;
        },
        getItem : function (id) {
            var obj = clone(spec.riaObject);
            var ds;
            for(i in spec.itemsDs) {
                if(spec.itemsDs[i].id == id) {
                    ds = spec.itemsDs[i];
                }
            }
            for(name in spec.extraItemTplValues) {
                var val = spec.extraItemTplValues[name].replace('${dsId}',ds.id);
                obj.setExtraTplValue(name,val.replace('${count}',i));
            }
            if(!ds) throw "could not find item with id:" + id;
            obj.setDs(ds);
            obj.setElement($('#' + spec.itemId + id));
            obj.setListReference(this);
            return obj;
        },
        setItemDs : function(ds) {
            id = ds.id;
            for(i in spec.itemsDs) {
                if(spec.itemsDs[i].id == id) {
                    spec.itemsDs[i] = ds;
                }
            }
        },
        addExtraTplValuesBeforeDisplay : function(ds) {},
        setItemId : function (itemId) {spec.itemId = itemId; return this;},
        setExtraTplValue : function (name, value) {spec.extraTplValues[name] = value; return this;},
        setTpls : function(tpls) {spec.tpls = tpls; return this;},
        setItemDecorators : function(itemDecorators) {spec.itemDecorators = itemDecorators; return this;},
        setRiaObject : function(riaObject) {spec.riaObject = riaObject;return this;},
        getRiaObject : function() {return spec.riaObject;},
        setViews : function(views) {spec.views = views; return this;},
        setActualView : function(actualView) {spec.actualView = actualView; return this;},
        setDs: function(ds) {spec.ds = ds;return this;},
        setItemsDs: function(itemsDs) {spec.itemsDs = itemsDs;return this;},
        getElement: function() {return spec.element;},
        setElement: function(newElement) {spec.element = newElement;return this;},
        getDs: function() {return spec.ds;},
        setDsVal: function( name, value) {spec.ds[name] = value;return this;},
        hide : function() {this.getElement().hide();return this;},
        show : function() {this.getElement().show();return this;},
        addCommand : function() {
            return function(name,func) {
                this[name] = function(json) {
                    func.apply(this,[spec,json]);
                }
                return this;
            }
        }()
    }
    return ret;
};